{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "from tqdm import tqdm\n",
    "import random\n",
    "import time\n",
    "sns.set()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_vocab(file, lower = False):\n",
    "    with open(file, 'r') as fopen:\n",
    "        data = fopen.read()\n",
    "    if lower:\n",
    "        data = data.lower()\n",
    "    vocab = list(set(data))\n",
    "    return data, vocab\n",
    "\n",
    "def embed_to_onehot(data, vocab):\n",
    "    onehot = np.zeros((len(data), len(vocab)), dtype = np.float32)\n",
    "    for i in range(len(data)):\n",
    "        onehot[i, vocab.index(data[i])] = 1.0\n",
    "    return onehot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "text, text_vocab = get_vocab('shakespeare.txt', lower = False)\n",
    "onehot = embed_to_onehot(text, text_vocab)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "65"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(text_vocab)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "learning_rate = 0.01\n",
    "batch_size = 32\n",
    "sequence_length = 64\n",
    "epoch = 3000\n",
    "num_layers = 2\n",
    "size_layer = 256\n",
    "possible_batch_id = range(len(text) - sequence_length - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Model:\n",
    "    def __init__(\n",
    "        self, num_layers, size_layer, dimension, sequence_length, learning_rate\n",
    "    ):\n",
    "        def lstm_cell():\n",
    "            return tf.nn.rnn_cell.LSTMCell(\n",
    "                size_layer, sequence_length\n",
    "            )\n",
    "\n",
    "        self.X = tf.placeholder(tf.float32, (None, None, dimension))\n",
    "        self.Y = tf.placeholder(tf.float32, (None, None, dimension))\n",
    "        attention_mechanism = tf.contrib.seq2seq.LuongAttention(\n",
    "            num_units = size_layer, memory = self.X\n",
    "        )\n",
    "        self.rnn_cells = tf.contrib.seq2seq.AttentionWrapper(\n",
    "            cell = tf.nn.rnn_cell.MultiRNNCell(\n",
    "                [lstm_cell() for _ in range(num_layers)]\n",
    "            ),\n",
    "            attention_mechanism = attention_mechanism,\n",
    "            attention_layer_size = size_layer,\n",
    "        )\n",
    "        self.initial_state = self.rnn_cells.zero_state(\n",
    "            dtype = tf.float32, batch_size = tf.shape(self.X)[0]\n",
    "        )\n",
    "        self.outputs, self.last_state = tf.nn.dynamic_rnn(\n",
    "            self.rnn_cells,\n",
    "            self.X,\n",
    "            initial_state = self.initial_state,\n",
    "            dtype = tf.float32,\n",
    "        )\n",
    "        rnn_W = tf.Variable(tf.random_normal((size_layer, dimension)))\n",
    "        rnn_B = tf.Variable(tf.random_normal([dimension]))\n",
    "        self.logits = (\n",
    "            tf.matmul(tf.reshape(self.outputs, [-1, size_layer]), rnn_W) + rnn_B\n",
    "        )\n",
    "        y_batch_long = tf.reshape(self.Y, [-1, dimension])\n",
    "        self.cost = tf.reduce_mean(\n",
    "            tf.nn.softmax_cross_entropy_with_logits(\n",
    "                logits = self.logits, labels = y_batch_long\n",
    "            )\n",
    "        )\n",
    "        self.optimizer = tf.train.RMSPropOptimizer(learning_rate, 0.9).minimize(\n",
    "            self.cost\n",
    "        )\n",
    "        self.correct_pred = tf.equal(\n",
    "            tf.argmax(self.logits, 1), tf.argmax(y_batch_long, 1)\n",
    "        )\n",
    "        self.accuracy = tf.reduce_mean(tf.cast(self.correct_pred, tf.float32))\n",
    "        seq_shape = tf.shape(self.outputs)\n",
    "        self.final_outputs = tf.reshape(\n",
    "            tf.nn.softmax(self.logits), (seq_shape[0], seq_shape[1], dimension)\n",
    "        )\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From <ipython-input-6-ae41de71fb25>:39: softmax_cross_entropy_with_logits (from tensorflow.python.ops.nn_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "\n",
      "Future major versions of TensorFlow will allow gradients to flow\n",
      "into the labels input on backprop by default.\n",
      "\n",
      "See `tf.nn.softmax_cross_entropy_with_logits_v2`.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "tf.reset_default_graph()\n",
    "sess = tf.InteractiveSession()\n",
    "model = Model(num_layers, size_layer, len(text_vocab), sequence_length, learning_rate)\n",
    "sess.run(tf.global_variables_initializer())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "seem\n"
     ]
    }
   ],
   "source": [
    "split_text = text.split()\n",
    "tag = split_text[np.random.randint(0, len(split_text))]\n",
    "print(tag)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train_random_sequence():\n",
    "    LOST, ACCURACY = [], []\n",
    "    pbar = tqdm(range(epoch), desc = 'epoch')\n",
    "    batch_x = np.zeros((batch_size, sequence_length, len(text_vocab)))\n",
    "    batch_y = np.zeros((batch_size, sequence_length, len(text_vocab)))\n",
    "    batch_id = random.sample(possible_batch_id, batch_size)\n",
    "    for n in range(sequence_length):\n",
    "        id1 = [k + n for k in batch_id]\n",
    "        id2 = [k + n + 1 for k in batch_id]\n",
    "        batch_x[:,n,:] = onehot[id1, :]\n",
    "        batch_y[:,n,:] = onehot[id2, :]\n",
    "    last_state, _ = sess.run([model.last_state, model.optimizer], feed_dict = {model.X: batch_x,\n",
    "                                                          model.Y: batch_y})\n",
    "    for i in pbar:\n",
    "        last_time = time.time()\n",
    "        batch_x = np.zeros((batch_size, sequence_length, len(text_vocab)))\n",
    "        batch_y = np.zeros((batch_size, sequence_length, len(text_vocab)))\n",
    "        batch_id = random.sample(possible_batch_id, batch_size)\n",
    "        for n in range(sequence_length):\n",
    "            id1 = [k + n for k in batch_id]\n",
    "            id2 = [k + n + 1 for k in batch_id]\n",
    "            batch_x[:,n,:] = onehot[id1, :]\n",
    "            batch_y[:,n,:] = onehot[id2, :]\n",
    "        last_state, _, loss, accuracy = sess.run([model.last_state, model.optimizer, \n",
    "                                                  model.cost, model.accuracy], \n",
    "                                       feed_dict = {model.X: batch_x, \n",
    "                                                    model.Y: batch_y,\n",
    "                                                    model.initial_state: last_state})\n",
    "        ACCURACY.append(accuracy); LOST.append(loss)\n",
    "        pbar.set_postfix(cost = loss, accuracy = accuracy)\n",
    "    return LOST, ACCURACY"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "epoch: 100%|██████████| 3000/3000 [05:20<00:00,  9.56it/s, accuracy=0.387, cost=2.12] \n"
     ]
    }
   ],
   "source": [
    "LOST, ACCURACY = train_random_sequence()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1080x360 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize = (15, 5))\n",
    "plt.subplot(1, 2, 1)\n",
    "EPOCH = np.arange(len(LOST))\n",
    "plt.plot(EPOCH, LOST)\n",
    "plt.xlabel('epoch'); plt.ylabel('loss')\n",
    "plt.subplot(1, 2, 2)\n",
    "plt.plot(EPOCH, ACCURACY)\n",
    "plt.xlabel('epoch'); plt.ylabel('accuracy')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "sentence_generated = tag\n",
    "onehot = embed_to_onehot(tag, text_vocab)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_based_sequence(length_sentence, argmax = False):\n",
    "    sentence_generated = tag\n",
    "    onehot = embed_to_onehot(tag, text_vocab)\n",
    "    batch_x = np.zeros((1, 1, len(text_vocab)))\n",
    "    batch_x[:, 0, :] = onehot[0, :]\n",
    "    last_state, prob = sess.run(\n",
    "            [model.last_state, model.final_outputs],\n",
    "            feed_dict = {model.X: batch_x},\n",
    "    )\n",
    "    for i in range(1, len(tag), 1):\n",
    "        batch_x = np.zeros((1, 1, len(text_vocab)))\n",
    "        batch_x[:, 0, :] = onehot[i, :]\n",
    "        last_state, prob = sess.run(\n",
    "            [model.last_state, model.final_outputs],\n",
    "            feed_dict = {model.X: batch_x, model.initial_state: last_state},\n",
    "        )\n",
    "\n",
    "    for i in range(length_sentence):\n",
    "        if argmax:\n",
    "            char = np.argmax(prob[0][0])\n",
    "        else:\n",
    "            char = np.random.choice(range(len(text_vocab)), p = prob[0][0])\n",
    "        element = text_vocab[char]\n",
    "        sentence_generated += element\n",
    "        onehot = embed_to_onehot(element, text_vocab)\n",
    "        batch_x = np.zeros((1, 1, len(text_vocab)))\n",
    "        batch_x[:, 0, :] = onehot[0, :]\n",
    "        last_state, prob = sess.run(\n",
    "            [model.last_state, model.final_outputs],\n",
    "            feed_dict = {model.X: batch_x, model.initial_state: last_state},\n",
    "        )\n",
    "\n",
    "    return sentence_generated"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "seem33nnQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ\n"
     ]
    }
   ],
   "source": [
    "print(generate_based_sequence(1000,True))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "seem33g$333,,,,,,,,,,,&NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN\n"
     ]
    }
   ],
   "source": [
    "print(generate_based_sequence(1000,False))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
